/**
主要回顾： 构造函数，构造代码块，this关键字。

构造函数：
    1.作用：初始化对应的对象。
    2.格式：
        修饰符 函数名(形式参数){
            函数体
        }
    3.注意事项：
        3.1 构造函数没有返回值类型
        3.2 构造函数的函数名必须与类名一致
        3.3 在创建对象时，JVM 自动根据参数调用相应的构造函数
        3.4 如果没有给一个类显式定义构造函数，java 编译器会自动为该类添加一个无参构造函数
        3.5 如果一个类已经有了显式定义的构造函数，则 java 编译器不会再添加无参构造函数(即使定义的构造函数不是无参的)
        3.6 构造函数可以以函数重载的形式存在多个
    
构造代码块：
    1.作用：给对象进行统一的初始化
    2.格式：
        {
            代码
        }
    3.注意事项：构造代码块在每创建该类的时对象时调用一次
    
this 关键字：代表了所属函数的调用者对象
    1.作用：
        1.1 通过 this 关键字指定访问成员变量
        1.2 通过 this 关键字在构造函数中调用另外一个构造函数
    2.注意事项：
        2.1 this 关键字调用其他构造函数时，必须要在第一个语句
        2.2 this 关键字调用构造函数时不能相互调用，否则会出现死循环
*/

class Baby{
    int id;
    String name;
    
    //构造代码块：给对象进行统一初始化
    {
        cry();	//每个对象创建的时候会执行
    }
    
    //无参构造函数：有了显式的构造函数后，编译器不会自动添加无参构造函数，需要自己添加
    public Baby(){
        
    }
    //1 个参数构造函数
    public Baby(String name){
        this.name = name;
    }
    //2 个参数构造函数
    public Baby(int id, String name){
        this(name);		//通过 this 关键字调用另外一个构造函数
        this.id = id;
    }
    
    public void cry(){
        System.out.println("crying...");
    }
}

/* 反编译出来的代码，可以看到规律
Compiled from "Demo0701.java"
class TestOrder {
    int i;

    public TestOrder();
        Code:
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: aload_0
             5: ldc           #2                  // int 222222222
             7: putfield      #3                  // Field i:I
            10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
            13: ldc           #5                  // String 构造代码块
            15: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            18: aload_0
            19: ldc           #7                  // int 111111111
            21: putfield      #3                  // Field i:I
            24: aload_0
            25: ldc           #8                  // int 333333333
            27: putfield      #3                  // Field i:I
            30: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
            33: ldc           #9                  // String 构造函数
            35: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
            38: return
        LineNumberTable:
            line 82: 0
            line 77: 4
            line 78: 10
            line 87: 18
            line 83: 24
            line 84: 30
            line 85: 38
}
*/
class TestOrder{
    //构造代码块先于构造函数执行，跟顺序无关
    {
        i = 222222222;    //构造代码块初始化
        System.out.println("构造代码块");
    }
    
    //构造函数最后执行
    public TestOrder(){
        i = 333333333;    //构造函数初始化
        System.out.println("构造函数");
    }
    //取决于它于构造代码块的位置，现在是它先执行，放在构造代码块后则后执行
    int i = 111111111;    //成员变量显式初始化    
}


class LearnConstructor{
    public static void main(String[] args){
        //测试 Baby 类的构造函数及构造代码块
        Baby b1 = new Baby();
        Baby b2 = new Baby(110, "Chuck");
        System.out.println(Integer.toString(b2.id) + b2.name);
        
        //测试构造代码块与构造函数的执行顺序
        System.out.println(new TestOrder().i);
    }
}